import { Inject, Provide, HttpStatus, Config } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { User } from '../entity/user.entity';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { Jwt, JwtService } from '@midwayjs/jwt';
import { CryptoService } from './crypto.service';
import { ICookieOptions } from '../interface';
import { WxService } from './wx.service';
import Utils from '../utils';
import * as crypto from 'crypto';
import { TencentService } from './tencent.service';
import { UploadFileInfo } from '@midwayjs/busboy';
import { UserInfoDto, UserPageQueryDto } from '../dto/user.dto';
import { Seller } from '../entity/seller.entity';
import { Role } from '../entity/role.entity';
import { RoleService } from './role.service';

@Provide()
export class UserService {
  /**
   * 微信登录JWT过期时间
   */
  public static readonly WX_JWT_LAST_LOGIN_TIME = '30d';

  /**
   * 网页登录JWT过期时间
   */
  public static readonly WEB_JWT_LAST_LOGIN_TIME = '2h';

  @Config('cookies')
  private cookieConfig: ICookieOptions;

  @Config('wxapp')
  private wxAppConfig: { appid: string };

  @Inject()
  private tencentService: TencentService;

  @Inject()
  private ctx: Context;

  @InjectEntityModel(User)
  userModel: Repository<User>;

  @InjectEntityModel(Seller)
  sellerModel: Repository<Seller>;

  @InjectEntityModel(Role)
  roleModel: Repository<Role>;

  @Inject()
  roleService: RoleService;

  @Inject()
  jwtService: JwtService;

  @Inject()
  wxService: WxService;

  @Inject()
  cryptoService: CryptoService;

  @Inject()
  private utils: Utils;

  async setJwt(userId: number = 5, client: 'web' | 'wxapp' = 'web') {
    const token = await this.jwtService.sign(
      {
        userId,
        client
      },
      {
        expiresIn:
          client === 'web'
            ? UserService.WEB_JWT_LAST_LOGIN_TIME
            : UserService.WX_JWT_LAST_LOGIN_TIME
      }
    );
    return this.utils.response.success(token);
  }

  async getJwt(token: string) {
    try {
      const decoded = (await this.jwtService.verify(token, {
        complete: true
      })) as Jwt.Jwt;
      console.log(decoded);
      return this.utils.response.success('ok');
    } catch (error) {
      return this.utils.response.fail('token 校验失败', 401);
    }
  }

  /**
   * 同步用户角色
   * @description 1、如果用户的roles为空，添加 normal角色
   * @description 2、如果seller表中存在该用户手机号的经销商记录，并且seller.status为启用，user.roles 添加 seller角色
   * @description 3、如果seller表中存在该用户手机号的经销商记录，并且seller.status为禁用，user.roles 移除 seller 角色
   * @description 4、如果seller表中不存在该用户手机号的经销商记录，user.roles 移除 seller 角色
   * @param user
   */
  async syncUserRole(user: User) {
    // 1. 如果用户的roles为空，添加 normal角色
    if (!user.roles || user.roles.length === 0) {
      user.roles = [this.roleService.getRoleByCode(Role.ROLE_NORMAL)];
    } else if (!user.roles.find(r => r.code === Role.ROLE_NORMAL)) {
      user.roles.push(this.roleService.getRoleByCode(Role.ROLE_NORMAL));
    }

    // 2. 查询seller表
    const seller = await this.sellerModel.findOne({
      where: { phone: user.user_phone }
    });
    const sellerRole = this.roleService.getRoleByCode(Role.ROLE_SELLER);

    if (seller) {
      if (seller.status === Seller.STATUS_ENABLE) {
        // 2、seller.status为启用，user.roles 添加 seller角色
        if (!user.roles.find(r => r.code === Role.ROLE_SELLER)) {
          user.roles.push(sellerRole);
        }
      } else if (seller.status === Seller.STATUS_DISABLE) {
        // 3、seller.status为禁用，user.roles 移除 seller 角色
        user.roles = user.roles.filter(r => r.code !== Role.ROLE_SELLER);
      }
    } else {
      // 4、seller表中不存在该用户手机号的经销商记录，user.roles 移除 seller 角色
      user.roles = user.roles.filter(r => r.code !== Role.ROLE_SELLER);
    }
    return user;
  }

  /**
   * 获取当前登录用户
   */
  async current() {
    const cookieToken = this.ctx.cookies.get(this.cookieConfig.tokenKey);

    let headerToken = this.ctx.headers[this.cookieConfig.tokenKey];
    if (Array.isArray(headerToken)) {
      headerToken = headerToken[0];
    }

    let authToken = this.ctx.headers.authorization;
    if (authToken && authToken.startsWith('Bearer ')) {
      authToken = authToken.slice(7);
    }

    // 统一获取 token，优先级可调整
    const token = cookieToken || headerToken || authToken;

    // 验证token
    try {
      const decoded = (await this.jwtService.verify(token, {
        complete: true
      })) as { payload: any };

      const client = decoded.payload.client;
      const userId = decoded.payload.userId;
      if (client !== 'web' && client !== 'wxapp') {
        return this.utils.response.fail('未登录', 401);
      }

      const user = await this.userModel
        .createQueryBuilder('user')
        .leftJoinAndSelect('user.roles', 'roles')
        .where({ user_id: userId })
        .getOne();

      if (!user) {
        return this.utils.response.fail('用户不存在', 401);
      }

      // 同步用户角色
      await this.syncUserRole(user);
      await this.userModel.save(user);

      return this.utils.response.success({
        userInfo: new UserInfoDto(user),
        token
      });
    } catch (error) {
      return this.utils.response.fail('登录已过期', 401);
    }
  }

  /**
   * 账号密码登录
   * @param account 账号
   * @param password md5加密后的密码
   * @description 数据库中存储的密码为  md5(password + ':' + md5(salt))
   * @returns
   */
  async login(account: string, password: string) {
    const user = await this.userModel
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'roles')
      .where('user.account = :account', { account })
      .addSelect('user.password')
      .getOne();

    if (!user || !user.password) {
      return this.utils.response.fail(
        '用户名或密码不正确',
        HttpStatus.UNAUTHORIZED
      );
    }

    const verify = this.cryptoService.verifyPassword(password, user.password);
    if (!verify) {
      return this.utils.response.fail(
        '用户名或密码不正确',
        HttpStatus.UNAUTHORIZED
      );
    }

    // 更新最后登录时间
    user.last_login_time = Date.now();
    // 同步用户角色
    await this.syncUserRole(user);
    await this.userModel.save(user);

    // 生成JWT令牌
    const token = await this.jwtService.sign(
      {
        userId: user.user_id,
        account: user.account,
        client: 'web'
      },
      {
        expiresIn: UserService.WEB_JWT_LAST_LOGIN_TIME
      }
    );
    // 写入cookie
    this.ctx.cookies.set(this.cookieConfig.tokenKey, token);

    return this.utils.response.success({
      userInfo: new UserInfoDto(user),
      token
    });
  }

  /**
   * 微信通过openid登录
   * @param openid
   * @returns
   */
  async loginByOpenId(openid: string) {
    const user = await this.userModel
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'roles')
      .where({ wechat_openid: openid })
      .getOne();

    if (!user) {
      // 用户存在，更新最后登录时间
      return this.utils.response.fail('未找到用户', 401);
    }

    user.last_login_time = Date.now();

    // 同步用户角色
    await this.syncUserRole(user);
    // 保存用户（更新或插入）
    await this.userModel.save(user);

    // 生成JWT令牌
    const token = await this.jwtService.sign(
      {
        userId: user.user_id,
        openid: user.wechat_openid,
        client: 'wxapp'
      },
      {
        expiresIn: UserService.WX_JWT_LAST_LOGIN_TIME
      }
    );

    return this.utils.response.success({
      userInfo: new UserInfoDto(user),
      token
    });
  }

  /**
   * 通过微信获取的临时code和phone_code登录或者注册
   * @param login_code
   * @param phone_code
   * @returns
   */
  async userCheck(login_code: string, phone_code: string) {
    const loginResult = await this.wxService.wxAppLogin(login_code);
    const phoneResult = await this.wxService.getUserPhoneNumber(phone_code);

    if (!loginResult.success) return loginResult;
    if (!phoneResult.success) return phoneResult;

    const { phoneNumber: phone_number } = phoneResult.data;

    let user = await this.userModel
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'roles')
      .where({ user_phone: phone_number })
      .getOne();

    if (!user) {
      const password = this.cryptoService.password(phone_number.slice(-6));

      // 用户不存在，创建新用户
      user = this.userModel.create({
        user_name: phone_number,
        user_phone: phone_number,
        wechat_openid: loginResult.data.openid,
        account: phone_number,
        password: password,
        wechat_nickname: '用户' + phone_number.slice(-6),
        user_avatar:
          'https://bbl-1329058988.cos.ap-beijing.myqcloud.com/stick/assets/avatar.png'
      });

      // 从seller中根据手机号查询是否已有经销商记录
      await this.syncUserRole(user);
      await this.userModel.save(user);
    }

    if (user.wechat_openid !== loginResult.data.openid) {
      return this.utils.response.fail('该手机号已被其他微信账号绑定');
    }

    // 生成JWT令牌
    const token = await this.jwtService.sign(
      {
        userId: user.user_id,
        openid: loginResult.data.openid,
        client: 'wxapp'
      },
      {
        expiresIn: UserService.WX_JWT_LAST_LOGIN_TIME
      }
    );

    return this.utils.response.success({
      userInfo: new UserInfoDto(user),
      token
    });
  }

  async decodeWxEncryptedData(target: string, iv: string, login_code: string) {
    const loginResult = await this.wxService.wxAppLogin(login_code);
    if (!loginResult.success) {
      return loginResult;
    }

    const { session_key } = loginResult.data;

    try {
      const encryptedDataBuffer = Buffer.from(target, 'base64');
      const key = Buffer.from(session_key, 'base64');
      const ivBuffer = Buffer.from(iv, 'base64');

      // 使用 aes-128-cbc 解密
      const decipher = crypto.createDecipheriv('aes-128-cbc', key, ivBuffer);
      decipher.setAutoPadding(true);

      const decrypted = Buffer.concat([
        decipher.update(encryptedDataBuffer),
        decipher.final()
      ]);

      const decodedData = JSON.parse(decrypted.toString('utf8'));

      console.log(decodedData, 'decodedData');

      // 校验 appid
      if (decodedData.watermark.appid !== this.wxAppConfig.appid) {
        return this.utils.response.fail('appid 不匹配', HttpStatus.BAD_REQUEST);
      }

      return this.utils.response.success(decodedData);
    } catch (err) {
      this.ctx.logger.error('解密失败:', err);
      return this.utils.response.fail(
        '解密失败',
        HttpStatus.INTERNAL_SERVER_ERROR
      );
    }
  }

  async wxUpdateUserInfo(file?: UploadFileInfo, wechat_nickname?: string) {
    if (!file && !wechat_nickname) {
      return this.utils.response.fail('请上传头像或输入昵称');
    }
    let upResult = null;
    if (file) {
      upResult = await this.tencentService.uploadFile(file);
      if (!upResult.success) return this.utils.response.fail('上传头像失败');
    }

    // 需要从jwt token中获取用户信息
    const token = this.utils.getToken();
    if (!token) return this.utils.response.fail('请先登录');

    const decoded = this.utils.decodeToken<{
      userId: string;
      openid: string;
      client: string;
      iat: number;
      exp: number;
    }>(token);
    if (!decoded) return this.utils.response.fail('token 无效');

    const user = await this.userModel
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'roles')
      .where({ wechat_openid: decoded.openid })
      .getOne();

    if (!user) return this.utils.response.fail('用户不存在');

    if (wechat_nickname) {
      user.wechat_nickname = wechat_nickname;
    }
    if (upResult) {
      user.user_avatar = upResult.data;
    }
    // 同步用户角色
    await this.syncUserRole(user);
    await this.userModel.save(user);

    return this.utils.response.success({
      userInfo: new UserInfoDto(user),
      token
    });
  }

  /**
   * 退出登录
   */
  async logout() {
    // 清除cookie
    this.ctx.cookies.set(this.cookieConfig.tokenKey, '', {
      httpOnly: true,
      secure: this.ctx.secure,
      sameSite: 'strict'
    });
    return this.utils.response.success();
  }

  /**
   * 分页查询非管理员用户
   * @param queryDto 
   */
  async getNormalUserPageList(queryDto: UserPageQueryDto) {
    const { userName, userPhone, pageSize, current } = queryDto;

    // 构建查询条件
    const qb = this.userModel.createQueryBuilder('user')
      .leftJoinAndSelect('user.roles', 'roles')
      .where('1=1');

    if (userName) {
      qb.andWhere('user.user_name LIKE :userName', { userName: `%${userName}%` });
    }
    if (userPhone) {
      qb.andWhere('user.user_phone LIKE :userPhone', { userPhone: `%${userPhone}%` });
    }

    // 只查询非管理员用户
    qb.andWhere(qb => {
      const subQuery = qb.subQuery()
        .select('role.id')
        .from('tb_role', 'role')
        .where('role.code = :adminCode')
        .getQuery();
      return `NOT EXISTS (
      SELECT 1 FROM tb_user_role ur
      WHERE ur.user_id = user.user_id
      AND ur.role_id = (${subQuery})
    )`;
    }).setParameter('adminCode', Role.ROLE_ADMIN);

    qb.skip((current - 1) * pageSize)
      .take(pageSize)
      .orderBy('user.user_id', 'DESC');

    const [list, total] = await qb.getManyAndCount();
    // 转换为 UserInfoDto 格式
    const userList = list.map(user => new UserInfoDto(user));

    return this.utils.response.success({
      list: userList,
      total,
      current,
      pageSize
    });
  }
}
